


























import numpy as np
import pandas as pd
import scipy.stats as stats


def _slope(ts, x=None):
    if x is None:
        x = np.arange(len(ts))
    log_ts = np.log(ts)
    slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_ts)
    return slope

class MyFactor(CustomFactor):
    """
    12 months Momentum
    Run a linear regression over one year (252 trading days) stocks log returns
    and the slope will be the factor value
    """
    inputs = [USEquityPricing.close]
    window_length = 252
           
    def compute(self, today, assets, out, close):
        x = np.arange(len(close))
        slope = np.apply_along_axis(_slope, 0, close, x.T)
        out[:] = slope








import alphalens as al


al.utils.get_clean_factor_and_forward_returns(factor,
                                              prices,
                                              groupby=None,
                                              binning_by_group=False,
                                              quantiles=5,
                                              bins=None,
                                              periods=(1, 5, 10),
                                              filter_zscore=20,
                                              groupby_labels=None,
                                              max_loss=0.35,
                                              zero_aware=False)











from quantopian.pipeline.filters import QTradableStocksUS


universe = QTradableStocksUS()








from quantopian.research import run_pipeline
from quantopian.pipeline import Pipeline
from quantopian.pipeline.classifiers.fundamentals import Sector 


pipe = Pipeline(
    columns = {
            'MyFactor' : MyFactor(mask=universe),
            'Sector' : Sector(mask=universe), # optional, useful to compute individual sector statistics
    },
    screen=universe
)





factors = run_pipeline(pipe, '2013-01-01', '2014-01-01', chunksize=250) # chunksize is optional
factors = factors.dropna()





print factors.head()





asset_list = factors.index.levels[1].unique()





prices = get_pricing(asset_list, start_date='2013-01-01', end_date='2014-02-01', fields='open_price')





prices.head()








factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=factors["MyFactor"],
    prices=prices,
    quantiles=5,
    periods=(1, 5, 10))





sector_labels = dict(Sector.SECTOR_NAMES)
sector_labels[-1] = "Unknown" # no dataset is perfect, better handle the unexpected
print(sector_labels)


factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=factors["MyFactor"],
    prices=prices,
    groupby=factors["Sector"],    # optional, useful to compute group statistics (e.g. sector)
    groupby_labels=sector_labels, # optional, use labels instead of numeric group information
    quantiles=5,
    periods=(1, 5, 10))


factor_data.head()











al.tears.create_full_tear_sheet(factor_data, long_short=True, group_neutral=False, by_group=False)





al.tears.create_summary_tear_sheet(factor_data, long_short=True, group_neutral=False)





al.tears.create_returns_tear_sheet(factor_data, long_short=True, group_neutral=False, by_group=False)

al.tears.create_information_tear_sheet(factor_data, group_neutral=False, by_group=False)

al.tears.create_turnover_tear_sheet(factor_data)

al.tears.create_event_returns_tear_sheet(factor_data, prices,
                                         avgretplot=(5, 15),
                                         long_short=True,
                                         group_neutral=False,
                                         std_bar=True,
                                         by_group=False)











al.tears.create_event_returns_tear_sheet(factor_data, prices,
                                         avgretplot=(2,10),
                                         long_short=True,
                                         group_neutral=False,
                                         std_bar=False,
                                         by_group=False)





al.tears.create_event_returns_tear_sheet(factor_data, prices,
                                         avgretplot=(2,10),
                                         long_short=False,
                                         group_neutral=False,
                                         std_bar=False,
                                         by_group=False)








al.tears.create_returns_tear_sheet(factor_data,
                                   long_short=True,
                                   group_neutral=False,
                                   by_group=True)









































al.tears.create_information_tear_sheet(factor_data,
                                       group_neutral=False,
                                       by_group=True)

















al.tears.create_turnover_tear_sheet(factor_data)























al.performance.create_pyfolio_input(factor_data,
                                    period,
                                    capital=None,
                                    long_short=True,
                                    group_neutral=False,
                                    equal_weight=False,
                                    quantiles=None,
                                    groups=None,
                                    benchmark_period='1D')








pf_returns, pf_positions, pf_benchmark = \
    al.performance.create_pyfolio_input(factor_data,
                                        period='5D',
                                        capital=1000000,
                                        long_short=True,
                                        group_neutral=False,
                                        equal_weight=True,
                                        quantiles=[1,5],
                                        groups=None,
                                        benchmark_period='1D')





import pyfolio as pf


pf.tears.create_full_tear_sheet(pf_returns,
                                positions=pf_positions,
                                #benchmark_rets=pf_benchmark, # optional, default to SPY
                                hide_positions=True)








from quantopian.research.experimental import get_factor_loadings, get_factor_returns


asset_list = factor_data.index.levels[1].unique()
start_date = factor_data.index.levels[0].min()
end_date   = factor_data.index.levels[0].max()

factor_loadings = get_factor_loadings(asset_list, start_date, end_date)
factor_returns = get_factor_returns(start_date, end_date)





factor_loadings.index.names = ['dt', 'ticker']


pf.tears.create_perf_attrib_tear_sheet(pf_returns,
                                       positions=pf_positions,
                                       factor_returns=factor_returns,
                                       factor_loadings=factor_loadings,      
                                       pos_in_dollars=True)











al.plotting.plot_quantile_statistics_table(factor_data)





alternative_binning_factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=factors["MyFactor"],
    prices=prices,
    quantiles=[0, .05, .30, .50, .70, .95, 1.00],
    bins=None,
    periods=(1, 5, 10))


al.plotting.plot_quantile_statistics_table(alternative_binning_factor_data)








from quantopian.pipeline.factors import RSI


pipe = Pipeline(
    columns = {
            'RSI' : RSI(mask=universe),
    },
    screen=universe
)
more_factors = run_pipeline(pipe, '2014-01-01', '2015-01-01')
asset_list = more_factors.index.levels[1].unique()
prices = get_pricing(asset_list, start_date='2014-01-01', end_date='2015-02-01', fields='open_price')





rsi_factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=more_factors["RSI"],
    prices=prices,
    quantiles=5,
    bins=None,
    periods=(1, 5, 10))


al.plotting.plot_quantile_statistics_table(rsi_factor_data)





rsi_factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=more_factors["RSI"],
    prices=prices,
    quantiles=None,
    bins=[0, 10, 20, 30, 70, 80, 90, 100],
    periods=(1, 5, 10))


al.plotting.plot_quantile_statistics_table(rsi_factor_data)











from quantopian.pipeline.data.sentdex import sentiment_free


pipe = Pipeline(
    columns = {
            'Sentdex' : sentiment_free.sentiment_signal.latest,
    },
    screen=universe
)
more_factors = run_pipeline(pipe, '2014-01-01', '2015-01-01')
asset_list = more_factors.index.levels[1].unique()
prices = get_pricing(asset_list, start_date='2014-01-01', end_date='2015-02-01', fields='open_price')


sentdex_factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=more_factors["Sentdex"],
    prices=prices,
    quantiles=None,
    bins=[-3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5 ],
    periods=(1, 2, 5),
    max_loss = 0.80 ) # allow 80% data loss since sentdex is not available for the full QTradableStocksUS


al.plotting.plot_quantile_statistics_table(sentdex_factor_data)











from quantopian.pipeline.factors import SimpleBeta, Returns
from quantopian.pipeline.data import Fundamentals

class Volatility(CustomFactor):
    inputs = [Returns(window_length=126)]
    window_length = 252
    def compute(self, today, assets, out, returns):
        out[:] = np.nanstd(returns, axis=0)
        
class Momentum(CustomFactor):
    inputs = [USEquityPricing.close]
    window_length = 252
    def compute(self, today, assets, out, prices):
        start = self.window_length
        out[:] = (prices[0] - prices[-start])/prices[-start]


market = symbols('SPY')

number_of_groups = 6

pipe = Pipeline(
    columns = {
            'market_cap' : Fundamentals.market_cap.latest.quantiles(number_of_groups),
            'B_to_M'     : Fundamentals.book_value_yield.latest.quantiles(number_of_groups),
            'Volatility' : Volatility(mask=universe).quantiles(number_of_groups),
            'Beta'       : SimpleBeta(market, 252).quantiles(number_of_groups),
            'Momentum'   : Momentum(mask=universe).quantiles(number_of_groups),
    },
    screen=universe
)

















intraday_factor = factors["MyFactor"]





intraday_factor = intraday_factor.unstack()
intraday_factor.index += pd.Timedelta('14h31m') # 14h31m is 09h31m at my current Timezone
intraday_factor = intraday_factor.stack()
intraday_factor.head()





forward_returns = []

# loop through each day in the factor DataFrame
for timestamp, daily_factor in intraday_factor.groupby(level=0):
    
    # equities in the universe at that particular day
    equities = daily_factor.index.levels[1]
    
    # we use get_pricing() with minute resolution to fetch the minute prices at that particular day
    start = timestamp
    end   = timestamp + pd.Timedelta('180m') # make sure to load enough data
    __prices = get_pricing(equities, start, end, frequency='minute', fields='price')

    if len(__prices) < 181:
        continue
        
    # use Alphalens to compute forward returns for 30m, 60m, 90m, 120m, 180m
    __forward_returns = al.utils.compute_forward_returns(daily_factor,
                                                         __prices,
                                                         periods=(30, 60, 90, 120, 180))
    forward_returns.append(__forward_returns)


forward_returns = pd.concat(forward_returns)
forward_returns.head()





intraday_factor_data = al.utils.get_clean_factor(factor=intraday_factor,
                                                 forward_returns=forward_returns)





al.tears.create_full_tear_sheet(intraday_factor_data)











class HistoricalClose(CustomFactor):
    inputs = [USEquityPricing.close]
    window_length = 2
    
    def compute(self, today, assets, out, close):
        out[:] = close[0]

event_mask = (USEquityPricing.close.latest < 5) & (HistoricalClose(mask=universe, window_length=2) >= 5)


pipe = Pipeline(
    columns = {
            'my_event' : event_mask,
    },
    screen=event_mask
)

events = run_pipeline(pipe, '2011-01-01', '2017-01-01')





events[:] = -1.0 # as this is negative Alphalens will trade the event with short positions
events.head()


asset_list = events.index.levels[1].unique()


prices = get_pricing(asset_list, start_date='2011-01-01', end_date='2017-03-01', fields='open_price')





event_data = al.utils.get_clean_factor_and_forward_returns(events, 
                                                           prices, 
                                                           quantiles=None,
                                                           bins=[-10,10], # bug in pandas explained above
                                                           periods=(1, 2, 3, 4, 5, 6, 10),
                                                           filter_zscore=None)


event_data.head()


al.tears.create_event_study_tear_sheet(event_data,
                                       prices,
                                       avgretplot=(3, 10),
                                       rate_of_ret=False,
                                       n_bars=100)



